/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ch.lab24.android.rtm;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;

import ch.lab24.android.rtm.provider.RTM;
import ch.lab24.android.rtm.provider.RTM.Notes;
import ch.lab24.android.rtm.provider.RTM.Tasks;
import ch.lab24.rtm.ServiceException;
import ch.lab24.rtm.ServiceImpl;
import ch.lab24.rtm.data.RtmTask;
import ch.lab24.rtm.data.RtmTaskList;
import ch.lab24.rtm.data.RtmTaskNote;
import ch.lab24.rtm.data.RtmTaskSeries;
import ch.lab24.rtm.data.RtmTasks;

public class RTMInvoker {

	private static final String API_KEY = "1234";
	private static final String SHARED_SECRET = "1111";
	private static final String APP_NAME = "Android RTM";
	
	private ServiceImpl mRtmService;
	private SharedPreferences mPreferences; 
    private ContentResolver mContentResolver;

	
	public RTMInvoker(Context context)
	{
		mPreferences = context.getSharedPreferences(RememberTheMilk.PREFERENCES_NAME, Context.MODE_PRIVATE);		
		mContentResolver = context.getContentResolver();
		
        String authToken = mPreferences.getString(RememberTheMilk.PREFERENCES_AUTH_TOKEN, "");
  		if (authToken != null)
  		{
			try
			{
		  		ch.lab24.rtm.ApplicationInfo appInfo = new ch.lab24.rtm.ApplicationInfo(API_KEY
						, SHARED_SECRET , APP_NAME, authToken); 	
		        mRtmService = new ch.lab24.rtm.ServiceImpl(appInfo, context);
			}
			catch (Exception ex)
			{
			
			}
  		}
	}
	
	public synchronized boolean update() throws ServiceException
	{
		
        try
        {

			Long lastSync = mPreferences.getLong(RememberTheMilk.PREFERENCES_LAST_SYNC, 0);
			// Todo: Date in UTC?
			Date now = new Date();
    		Long lastSyncAfter = now.getTime();
    		Date lastSyncDate = null; 
    		GregorianCalendar calendar = new GregorianCalendar();
    		calendar.setTime(new Date(lastSync));
    		if (lastSync > 0)
    			lastSyncDate = new Date(lastSync - (calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)) );
	        
    		// "status:incomplete"
        	RtmTasks vTasks = mRtmService.tasks_getList(null, (lastSyncDate == null) ? "status:incomplete" : null, lastSyncDate);
        	for ( Iterator<RtmTaskList> i = vTasks.getLists().iterator(); i.hasNext(); )
        	{
        		RtmTaskList vList = i.next();
        		for ( Iterator<RtmTaskSeries> j = vList.getSeries().iterator(); j.hasNext(); )
            	{
        			RtmTaskSeries vTaskSeries = j.next();
        			ContentValues values = new ContentValues();
        	       
        	        // Make sure that the fields are all set            	                    	        
        	        if (values.containsKey(RTM.Tasks.TASKID) == false) 
        	        	values.put(RTM.Tasks.TASKID, vTaskSeries.getId());
        	        if (values.containsKey(RTM.Tasks.NAME) == false) 
        	        	values.put(RTM.Tasks.NAME, vTaskSeries.getName());
        	        if (values.containsKey(RTM.Tasks.URL) == false) 
        	        	values.put(RTM.Tasks.URL, vTaskSeries.getURL());
        	        if (values.containsKey(RTM.Tasks.CREATED) == false) 
        	            values.put(RTM.Tasks.CREATED, vTaskSeries.getCreated().getTime());
        	        if (values.containsKey(RTM.Tasks.MODIFIED) == false) 
        	            values.put(RTM.Tasks.MODIFIED, vTaskSeries.getModified().getTime());
        	        if (vTaskSeries.getTask() != null)
        	        {
	        	        if (values.containsKey(RTM.Tasks.TAGS) == false) 
	        	        	values.put(RTM.Tasks.TAGS, vTaskSeries.getTags().toString());
	        	        if (vTaskSeries.getTask().getDue() != null && values.containsKey(RTM.Tasks.DUE) == false) 	        	        	
	        	        	values.put(RTM.Tasks.DUE, vTaskSeries.getTask().getDue().getTime());
	        	        else
	        	        	values.put(RTM.Tasks.DUE, RememberTheMilk.NULL_DATE);	        	        	
	        	        if (values.containsKey(RTM.Tasks.HAS_DUE) == false) 
	        	        	values.put(RTM.Tasks.HAS_DUE, vTaskSeries.getTask().getHasDueTime());
	        	        if (vTaskSeries.getTask().getAdded() != null && values.containsKey(RTM.Tasks.ADDED) == false) 
	        	        	values.put(RTM.Tasks.ADDED, vTaskSeries.getTask().getAdded().getTime());
	        	        if (vTaskSeries.getTask().getCompleted() != null && values.containsKey(RTM.Tasks.COMPLETED) == false) 
	        	        	values.put(RTM.Tasks.COMPLETED, vTaskSeries.getTask().getCompleted().getTime());
	        	        if (vTaskSeries.getTask().getDeleted() != null && values.containsKey(RTM.Tasks.DELETED) == false) 
	        	        	values.put(RTM.Tasks.DELETED, vTaskSeries.getTask().getDeleted().getTime());
	        	        if (vTaskSeries.getTask().getPriority() != null && values.containsKey(RTM.Tasks.PRIORITY) == false) 	        	        	
	        	        	values.put(RTM.Tasks.PRIORITY, RtmTask.convertPriority(vTaskSeries.getTask().getPriority()));
	        	        if (values.containsKey(RTM.Tasks.POSTPONED) == false) 
	        	        	values.put(RTM.Tasks.POSTPONED, vTaskSeries.getTask().getPostponed());
	        	        if (values.containsKey(RTM.Tasks.ESTIMATE) == false) 
	        	        	values.put(RTM.Tasks.ESTIMATE, vTaskSeries.getTask().getEstimate());
        	        }
        	        long rowId = 0;
        	        // test if entry already in DB (Insert or Update)
        	        Cursor c = mContentResolver.query(RTM.Tasks.CONTENT_URI
        	        		, new String[] { Tasks._ID }
        	        		, RTM.Tasks.TASKID + " = ?"
        	        		, new String[] {vTaskSeries.getId()}, null);
        	        if (c.getCount() == 0)
        	        	rowId = ContentUris.parseId(mContentResolver.insert(RTM.Tasks.CONTENT_URI, values));
        	        else
        	        {
        	        	c.moveToFirst();
        	        	rowId = c.getLong(c.getColumnIndex(RTM.Tasks._ID));
        	        	mContentResolver.update(Uri.withAppendedPath(Tasks.CONTENT_URI, new Long(rowId).toString())
        	        			, values, null, null);
        	        }
        	        c.close();
        	        
        	        if (rowId > 0)
        	        {
            	        // test if entry already in DB (Insert or Update)
            	        c = mContentResolver.query(RTM.Notes.CONTENT_URI
            	        		, new String[] { Notes._ID }
		    	        		, RTM.Notes.TASKID + " = ?"
		    	        		, new String[] {(new Long(rowId)).toString()}, null);
            	        int counter = 0;
            	        if (vTaskSeries.getNotes() != null)
            	        	counter = vTaskSeries.getNotes().getNotes().size();
            	        // delete all notes first, because we want to get the Changes...
            	        if (c.getCount() != counter && c.getCount() > 0)
            	        	mContentResolver.delete(Notes.CONTENT_URI,  RTM.Notes.TASKID +"=" + (new Long(rowId)).toString(), null);
	        	        c.close();
	        	        
            	        if (vTaskSeries.getNotes() != null)
	        	        {
		            		for ( Iterator<RtmTaskNote> k = vTaskSeries.getNotes().getNotes().iterator(); k.hasNext(); )
		                	{
		            			RtmTaskNote vTaskNote = k.next();
		            	        ContentValues contentValues = new ContentValues();
		
		            	        // Make sure that the fields are all set            	                    	        
		            	        if (contentValues.containsKey(RTM.Notes.NOTESID) == false) 
		            	        	contentValues.put(RTM.Notes.NOTESID, vTaskNote.getId());
		            	        if (contentValues.containsKey(RTM.Notes.TASKID) == false) 
		            	        	contentValues.put(RTM.Notes.TASKID, rowId);
		            	        if (contentValues.containsKey(RTM.Notes.TITLE) == false) 
		            	        	contentValues.put(RTM.Notes.TITLE, vTaskNote.getTitle());
		            	        if (contentValues.containsKey(RTM.Notes.TEXT) == false) 
		            	        	contentValues.put(RTM.Notes.TEXT, vTaskNote.getText());
		            	        if (contentValues.containsKey(RTM.Notes.CREATED) == false) 
		            	        	contentValues.put(RTM.Notes.CREATED, vTaskNote.getCreated().getTime());
		            	        if (contentValues.containsKey(RTM.Notes.MODIFIED) == false) 
		            	        	contentValues.put(RTM.Notes.MODIFIED, vTaskNote.getModified().getTime());
		
		            	        // test if entry already in DB (Insert or Update)
		            	        c = mContentResolver.query(RTM.Notes.CONTENT_URI
		            	        		, new String[] { Notes._ID }
				    	        		, RTM.Notes.NOTESID + " = ?"
				    	        		, new String[] {vTaskNote.getId()}, null);
		            	        
		            	        if (c.getCount() == 0)
		            	        	mContentResolver.insert(RTM.Notes.CONTENT_URI, contentValues);
		            	        else
		            	        {
		            	        	c.moveToFirst();
		            	        	rowId = c.getLong(c.getColumnIndex(RTM.Tasks._ID));
		            	        	mContentResolver.update(Uri.withAppendedPath(Notes.CONTENT_URI
		            	        			, new Long(rowId).toString())
		            	        			, contentValues, null, null);
		            	        	
		            	        }		            	        	
		            	        c.close();
		            	        
		                	}
	        	        }
        	        }
            	}

        	} 
	    	SharedPreferences.Editor editor = mPreferences.edit();
	    	editor.putLong(RememberTheMilk.PREFERENCES_LAST_SYNC, lastSyncAfter);
	    	editor.commit();        		        
        }
        catch (ServiceException se)
        {
        	int responseCode = se.getResponseCode();
			// set authToken to null if we can't login.
			if (responseCode == 98)
			{
		    	SharedPreferences.Editor editor = mPreferences.edit();
		        editor.putString(RememberTheMilk.PREFERENCES_AUTH_TOKEN, null);
		        editor.commit();
			}        	
        	throw se;
        }
        catch (Exception e)
        {
        	e.printStackTrace();
        } 
		
		return true;
	}
}
